﻿using DFGK_WMS.Context;
using DFGK_WMS.IRepository;
using DFGK_WMS.IRepository.IService;
using DFGK_WMS.IRepository.蒙牛;
using DFGK_WMS.Model;
using DFGK_WMS.Model.Enum;
using DFGK_WMS.Model.Models;
using DFGK_WMS.Model.Models.PDA;
using DFGK_WMS.Repository.Service;
using Microsoft.EntityFrameworkCore;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DFGK_WMS.Repository.蒙牛
{
    public class MNStackingStorageService : BaseService, IMNStackingStorageService
    {
        protected readonly static object _lockObj = new object();

        public ITCellRepository TCellRepository { get; }
        public DFGK_DB Context { get; }

        public MNStackingStorageService(ISqlSugarClient client, ITCellRepository tCellRepository, DFGK_DB context) : base(client)
        {
            TCellRepository = tCellRepository;
            Context = context;
        }
        /// <summary>
        /// 组垛及入库
        /// </summary>
        /// <param name="errMsg"></param>
        /// <param name="data"></param>
        /// <param name="Getcell"></param>
        /// <returns></returns>
        public bool BuildCreateStackingStorageEF(out string errMsg, PalletTallyInputModel data, ref List<TCell> Getcell)
        {
            errMsg = string.Empty;
            bool result = false;
            (bool, string, TReceivingOrderDetail) arr = ValidateStatusEF(data.OrderDetailId);

            if (arr.Item1 == false)
            {
                errMsg = arr.Item2;
                return false;
            }
            TReceivingOrderDetail? item3 = arr.Item3;

            int heightType = (int)EmHeightType.H1150;
            decimal enabledNum = item3.Qty.GetValueOrDefault() - item3.StackedQty.GetValueOrDefault();
            if (enabledNum - data.TotalNum < 0 || data.TotalNum <= 0)
            {
                errMsg = "数量超出，最多还能组" + enabledNum.ToString() + item3.UnitName;
                return false;
            }
            var material = Context.TMaterials.AsNoTracking().FirstOrDefault(m => m.Id == item3.MaterialId);

            if (material == null)
            {
                errMsg = "未找到物料数据";
                return false;

            }

            if (material.Code != data.PalletPackage.MaterialCode)
            {
                errMsg = "包装信息中的物料与单据物料不一致";
                return false;
            }
            Model.Models.PalletBindMaterialModel palletBindMaterialModel = new Model.Models.PalletBindMaterialModel()
            {
                PalletBarcode = data.PalletBarcode,
                LogicPartCode = data?.LogicPartCode,
                MaterialPackageBindModel = new Model.Models.MaterialPackageBindModel()
                {
                    OrderDetailId = data.OrderDetailId.Value,
                    MaterialCode = data.PalletPackage.MaterialCode,
                    Barcodes = data.PalletPackage.Barcodes,
                    Qty = data.TotalNum,
                }
            };

            TStation station = Context.TStations.FirstOrDefault(r => r.WhId == data.WarehouseId);
            if (station is null)
            {
                errMsg = "请配置站台";
                return false;
            }

            TStackingStorage storageModel = Context.TStackingStorages.FirstOrDefault(r => r.Status == 1 && r.PalletBarcode == data.PalletBarcode);
            if (storageModel != null)
            {
                errMsg = "托盘已在组垛中";
                return false;
            }
            var getPall = Context.TPallets.FirstOrDefault(x => x.PalletBarcode == data.PalletBarcode);
            if (getPall is null || getPall.Status == 0)
            {
                errMsg = "未查询出此托盘：" + data.PalletBarcode;
                return false;
            }
            if (getPall.Status == 0)
            {
                errMsg = "托盘已被禁用：" + data.PalletBarcode;
                return false;
            }
            string palletBarcode = palletBindMaterialModel.PalletBarcode;
            int OrderId = palletBindMaterialModel.MaterialPackageBindModel.OrderDetailId;
            var orderDetail = Context.TReceivingOrderDetails.FirstOrDefault(x => x.Id == OrderId);
            decimal? materialNum = 0;
            materialNum = palletBindMaterialModel.MaterialPackageBindModel.Qty;
            TCell allocateCell = null;
            try
            {
                int stackingId = 0;
                string LogicPartCode = "";
                var tackingStorage = Context.TStackingStorages.FirstOrDefault(x => x.PalletBarcode == palletBarcode && x.RelatedOrderDetailId == OrderId && x.WarehouseCode == orderDetail.WarehouseCode && x.Status == 1);
                if (tackingStorage != null && tackingStorage.Id > 0)
                {
                    stackingId = tackingStorage.Id;
                }
                else
                {

                    var pallet = Context.TPallets.FirstOrDefault(x => x.PalletBarcode == palletBarcode);

                    if (pallet is null || string.IsNullOrWhiteSpace(pallet.PalletBarcode))
                    {
                        errMsg = "当前托盘不存在";
                        return false;
                    }
                    if (pallet.Type == (int)PalletTypeEnum.Pallet)
                    {
                        LogicPartCode = "TuoPan";
                    }
                    else if (pallet.Type == (int)PalletTypeEnum.Box64)
                    {
                        LogicPartCode = "Box6040";
                    }
                    else if (pallet.Type == (int)PalletTypeEnum.Box86)
                    {
                        LogicPartCode = "Box8060";
                    }

                    TStackingStorage chStacking = new TStackingStorage();
                    #region 垛包装数据保存
                    if (palletBarcode != null)
                    {
                        chStacking.WarehouseName = orderDetail.WarehouseName;
                        chStacking.WarehouseCode = orderDetail.WarehouseCode;
                        chStacking.BillType = (int)orderDetail.BillType.GetValueOrDefault();
                        chStacking.RelatedOrderDetailId = OrderId;
                        chStacking.Status = 1;
                        chStacking.PalletBarcode = palletBarcode;
                        chStacking.Qty = materialNum;
                        chStacking.PackQty = 1;
                        chStacking.AreaCode = "";
                        chStacking.LogicalPartCode = LogicPartCode;
                        chStacking.MaterialId = orderDetail.MaterialId;
                        chStacking.MaterialCode = orderDetail.MaterialCode;
                        chStacking.MaterialName = orderDetail.MaterialName;
                        chStacking.Articlebarcode = orderDetail.Articlebarcode;
                        chStacking.MaterialKeyId = orderDetail.MaterialKeyId;
                        chStacking.CreateUserId = data.UserId;
                        chStacking.CreateUserName = data.UserName;
                        chStacking.BatchNo = orderDetail.BatchNo;
                        chStacking.SmallBatchNo = orderDetail.SmallBatchNo;
                        chStacking.CreateDate = DateTime.Now;
                        chStacking.Fifodate = DateTime.Now;
                        chStacking.ParentPalletBarcode = palletBarcode;
                        //chStacking.ExpectedLocation = cell.Code;
                        Context.TStackingStorages.Add(chStacking);
                        if (Context.SaveChanges() <= 0)
                        {
                            errMsg = "保存垛主表数据失败";
                            return false;
                        }
                        stackingId = chStacking.Id;
                    }

                    allocateCell = GetOneCell(station, orderDetail, heightType, out string errorMsg, palletBindMaterialModel);
                    if (allocateCell == null)
                    {
                        if (string.IsNullOrEmpty(errorMsg) || errorMsg == "")
                        {
                            errMsg = "无可用仓位";
                        }
                        else
                        {
                            errMsg = errorMsg;
                        }
                        return false;
                    }
                    Getcell.Add(allocateCell);
                    //更新托盘
                    var pall = Context.TPallets.FirstOrDefault(p => p.Id == pallet.Id);
                    pall.WarehouseId = allocateCell.Id;
                    pall.LocationCode = allocateCell.Code;
                    pall.LocationName = allocateCell.Name;
                    pall.ErplocationName = allocateCell.Erpcode;
                    pall.ModifyDate = DateTime.Now;
                    Context.TPallets.Update(pall);
                    if (Context.SaveChanges() <= 0)
                    {
                        errMsg = "更新托盘货位信息失败";
                        return false;
                    }

                    int? fullStatus = null;
                    if (orderDetail.BillType == (int)EmInBillType.EmptyPalletIn)
                    {
                        fullStatus = 3;
                    }
                    else
                    {
                        fullStatus = 1;
                    }

                    //锁仓位
                    var cell = Context.TCells.AsNoTracking().FirstOrDefault(x => x.Id == allocateCell.Id);
                    cell.BusinessType = (int)EmBusinessType.In;
                    cell.IsLock = true;
                    cell.FullStatus = (int)fullStatus;
                    cell.Status = (int)EmCellStatus.Lock;
                    cell.ModifyDate = DateTime.Now;
                    Context.TCells.Update(cell);

                    if (Context.SaveChanges() <= 0)
                    {
                        errMsg = "仓位锁定失败";
                        return false;
                    }
                    var updTss = Context.TStackingStorages.Find(chStacking.Id);
                    if (updTss == null)
                    {
                        errMsg = "找不到";
                        return false;
                    }
                    updTss.ExpectedLocation = cell.Code;
                    Context.TStackingStorages.Update(updTss);
                    if (Context.SaveChanges() <= 0)
                    {
                        errMsg = "保存垛主表数据失败";
                        return false;
                    }

                    //更新入库单状态及仓位
                    TReceivingOrderDetail? receivingOrderDetail = Context.TReceivingOrderDetails.FirstOrDefault(r => r.Id == OrderId);
                    receivingOrderDetail.LocationId = allocateCell.Id;
                    receivingOrderDetail.LocationCode = allocateCell.Code;
                    receivingOrderDetail.LogicalPartCode = allocateCell.LogicalPartCode;
                    receivingOrderDetail.LocationName = allocateCell.Name;
                    receivingOrderDetail.StackedQty = data.TotalNum;
                    //Status = 3,
                    receivingOrderDetail.AuditDate = DateTime.Now;
                    receivingOrderDetail.AuditUserId = data.UserId;
                    receivingOrderDetail.AuditUserName = data.UserName;
                    Context.TReceivingOrderDetails.Update(receivingOrderDetail);
                    if (Context.SaveChanges() <= 0)
                    {
                        errMsg = "更新入库单失败";
                        return false;
                    }
                    #endregion
                }
                result = stackingId > 0;
                if (!result)
                {
                    errMsg = "保存垛主表数据失败";
                    return false;
                }
                if (allocateCell is null)
                {
                    errMsg = "保存垛主表数据失败";
                    return false;
                }
                result = ExecCreateInstruct(out errMsg, orderDetail, station, palletBindMaterialModel, allocateCell.Code);
                if (!result)
                {
                    errMsg = "入库失败" + errMsg;
                     return false;
                }
            }
            catch (Exception ex)
            {
                errMsg = "保存组箱数据失败: " + ex.Message;
                return false;
                throw;
            }
            return true;
        }

        /// <summary>
        /// 开始入库
        /// </summary>
        /// <param name="errorMsg"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public bool ExecCreateInstruct(out string errorMsg, params object[] data)
        {
            errorMsg = "";
            if (data == null || data.Length < 4)
            {
                errorMsg = "参数错误";
                return false;
            }
            TReceivingOrderDetail orderDetail = data[0] as TReceivingOrderDetail;
            int heightType = (int)EmHeightType.H1150;
            TStation srcStation = data[1] as TStation;
            string ActualLocation = data[3] as string;
            Model.Models.PalletBindMaterialModel palletBind = data[2] as Model.Models.PalletBindMaterialModel;
            if (orderDetail == null || palletBind == null || srcStation == null || ActualLocation == null)
            {
                errorMsg = "参数错误";
                return false;
            }
            //更新收货单明细表的组垛数量、保存垛主表信息、修改垛明细表的垛主表主键id
            string palletBarcode = palletBind.PalletBarcode;
            
            if (orderDetail.SourceType == 4)
            {
                
                var Inventories = Context.TInventory.FirstOrDefault(r => r.PalletBarcode == palletBind.PalletBarcode);
                if (Inventories is null)
                {
                    errorMsg = "托盘未存在库存中";
                    return false;
                }

                var stackingStorage = Context.TStackingStorages.FirstOrDefault(s => s.RelatedOrderDetailId == orderDetail.Id && s.PalletBarcode == palletBind.PalletBarcode && s.Status == 1);
                if (stackingStorage is null)
                {
                    errorMsg = "无组垛信息";
                    return false;
                }
                stackingStorage.ActualLocation = ActualLocation;
                Context.TStackingStorages.Update(stackingStorage);
                if (Context.SaveChanges() <= 0)
                {
                    errorMsg = "修改实际仓位失败";
                    return false;
                }

                // 查看是否需要更新仓位 预留和实际的仓位是否一样
                if (stackingStorage.ExpectedLocation != stackingStorage.ActualLocation)
                {
                    //查询托盘是为了后面更新托盘
                    var pallet = Context.TPallets.FirstOrDefault(x => x.PalletBarcode == palletBarcode);
                    if (pallet == null)
                    {
                        errorMsg = "该托盘未维护";
                        return false;
                    }
                    //更新托盘
                    var Actualcell = Context.TCells.FirstOrDefault(x => x.Code == stackingStorage.ActualLocation);
                    if (Actualcell is null)
                    {
                        errorMsg = "未找到仓位:"+ stackingStorage.ActualLocation;
                        return false;
                    }
                    var pall = Context.TPallets.FirstOrDefault(p => p.Id == pallet.Id);
                    pall.WarehouseId = Actualcell.Id;
                    pall.LocationCode = Actualcell.Code;
                    pall.LocationName = Actualcell.Name;
                    pall.ErplocationName = Actualcell.Erpcode;
                    pall.ModifyDate = DateTime.Now;
                    Context.TPallets.Update(pall);
                    if (Context.SaveChanges() <= 0)
                    {
                        errorMsg = "托盘更新失败";
                        return false;
                    }

                    //修改仓位
                    var cell = Context.TCells.FirstOrDefault(x => x.Code == stackingStorage.ExpectedLocation);
                    cell.BusinessType = (int)EmBusinessType.None;
                    cell.IsLock = false;
                    cell.FullStatus = 0;
                    cell.Status = (int)EmCellStatus.Normal;
                    cell.ModifyDate = DateTime.Now;
                    Context.TCells.Update(cell);
                    if (Context.SaveChanges() <= 0)
                    {
                        errorMsg = "预留仓位修改失败";
                        return false;
                    }
                }

                var tPutawayOrder = Context.TPutawayOrders.FirstOrDefault(s => s.RelatedOrderDetailId == Inventories.RelatedOrderDetailId);
                tPutawayOrder.RelatedOrderDetailId = stackingStorage.RelatedOrderDetailId;
                tPutawayOrder.Status = 4;
                Context.Update(tPutawayOrder);
                if (Context.SaveChanges() <= 0)
                {
                    errorMsg = "修改库存仓位失败";
                    return false;
                }
                //修改库存的信息(修改组垛仓位)
                var cellObj = Context.TCells.FirstOrDefault(s => s.Code == stackingStorage.ActualLocation);
                if (cellObj == null)
                {
                    errorMsg = "找不到仓位code:" + stackingStorage.ActualLocation;//修改组垛仓位
                    return false;
                }

                Inventories.LocationCode = cellObj.Code;
                Inventories.LocationName = cellObj.Name;
                Inventories.LocationId = cellObj.Id;
                Inventories.RelatedOrderDetailId = stackingStorage.RelatedOrderDetailId;
                Inventories.Status = 3;//修改库存状态为入库在途
                Inventories.TotalWeight = palletBind.MaterialPackageBindModel.Qty * GetMaterialTonnagefactor(orderDetail.MaterialCode);//总重量等于入库数量 * 物料吨数系数
                Context.TInventory.Update(Inventories);
                if (Context.SaveChanges() <= 0)
                {
                    errorMsg = "修改库存仓位失败";
                    return false;
                }


                if (orderDetail.Qty == orderDetail.StackedQty)
                {
                    var Instructobj = Context.TInstructs.FirstOrDefault(i => i.RelatedOrderDetailId == orderDetail.Id);
                    if (Instructobj is null)
                    {
                        errorMsg = "指令表查询错误";
                        return false;
                    }
                    var isok = ExecInstructFinished(Instructobj, out errorMsg);
                    if (!isok)
                    {
                        errorMsg = errorMsg;
                        return false;
                    }
                    return true;
                }
                else
                {
                    errorMsg = "组垛数量和入库数量不一致";
                    return false;
                }
            }

            TInstruct instruct = null;
            List<string> packageBarcodes = new List<string>();

            int cellId;
            TCell allocateCell = null;
            decimal? materialNum = 0;
            decimal? price = 0;
            lock (_lockObj)
            {
                bool result = false;
                TPallet pallet = null;

                var invCount = Context.TInventory.FirstOrDefault(x => x.Status == 1 && x.PalletBarcode == palletBarcode);

                if (invCount is not null)
                {
                    errorMsg = "当前垛已经存在库存";
                    return false;
                }
                if (orderDetail.Status == (int)EmBillStatus.Create)
                {
                    errorMsg = "入库单未启动";
                    return false;
                }
                if (orderDetail.Status == (int)EmBillStatus.Finished || orderDetail.Status == (int)EmBillStatus.MandatoryFinished)
                {
                    errorMsg = "入库单已完成";
                    return false;
                }
                if (orderDetail.Status != (int)EmBillStatus.Executing)
                {
                    errorMsg = "当前入库单未执行";
                    return false;
                }
                if (orderDetail.Price.HasValue)
                {
                    price = orderDetail.Price;
                }
                bool outInstructCount = Context.TInstructs.Any(x => x.WarehouseCode == orderDetail.WarehouseCode && x.Status == 2 && x.BusinessType == (int)EmBusinessType.Out && x.IsSuspend == false && x.ExpectedToLocation == srcStation.Code);
                if (outInstructCount)
                {
                    errorMsg = "有出库指令未完成，不能执行入库";
                    return false;
                }
                TMaterial material = Context.TMaterial.FirstOrDefault(x => x.Id == orderDetail.MaterialId);
                if (material == null)
                {
                    errorMsg = "订单明细物料数据不存在";
                    return false;
                }
                pallet = Context.TPallets.FirstOrDefault(x => x.PalletBarcode == palletBarcode);
                if (pallet == null)
                {
                    errorMsg = "该托盘未维护";
                    return false;
                }
                if (pallet.Status == 0)
                {
                    errorMsg = "该托盘已被禁用";
                    return false;
                }

                var stackingStorage = Context.TStackingStorages.FirstOrDefault(s => s.RelatedOrderDetailId == orderDetail.Id && s.PalletBarcode == palletBind.PalletBarcode && s.Status == 1);
                if (stackingStorage is null)
                {
                    errorMsg = "无组垛信息";
                    return false;
                }
                stackingStorage.ActualLocation = ActualLocation;
                Context.TStackingStorages.Update(stackingStorage);
                if (Context.SaveChanges() <= 0)
                {
                    errorMsg = "修改实际仓位失败";
                    return false;
                }

                // 查看是否需要更新仓位 预留和实际的仓位是否一样
                if (stackingStorage.ExpectedLocation != stackingStorage.ActualLocation)
                {
                    //更新托盘
                    var Actualcell = Context.TCells.FirstOrDefault(x => x.Code == stackingStorage.ActualLocation);

                    var pall = Context.TPallets.FirstOrDefault(p => p.Id == pallet.Id);
                    pall.WarehouseId = Actualcell.Id;
                    pall.LocationCode = Actualcell.Code;
                    pall.LocationName = Actualcell.Name;
                    pall.ErplocationName = Actualcell.Erpcode;
                    pall.ModifyDate = DateTime.Now;
                    Context.TPallets.Update(pall);
                    if (Context.SaveChanges() <= 0)
                    {
                        errorMsg = "托盘更新失败";
                        return false;
                    }

                    //修改仓位
                    var cell = Context.TCells.FirstOrDefault(x => x.Code == stackingStorage.ExpectedLocation);
                    cell.BusinessType = (int)EmBusinessType.None;
                    cell.IsLock = false;
                    cell.FullStatus = 0;
                    cell.Status = (int)EmCellStatus.Normal;
                    cell.ModifyDate = DateTime.Now;
                    Context.TCells.Update(cell);
                    if (Context.SaveChanges() <= 0)
                    {
                        errorMsg = "预留仓位修改失败";
                        return false;
                    }
                }

                if (stackingStorage == null || string.IsNullOrEmpty(stackingStorage.LogicalPartCode))
                {
                    errorMsg = "未选择逻辑分区";
                    return false;
                }
                if (stackingStorage.LogicalPartCode == "Box8060" && pallet.Type != 1)
                {
                    errorMsg = "逻辑分区与料箱不匹配";
                    return false;
                }
                else if (stackingStorage.LogicalPartCode == "Box6040" && pallet.Type != 2)
                {
                    errorMsg = "逻辑分区与料箱不匹配";
                    return false;
                }
                
                allocateCell = Context.TCells.FirstOrDefault(c => c.Code == stackingStorage.ActualLocation); //修改组垛仓位

                if (allocateCell is null)
                {
                    errorMsg = "未找到仓位:" + stackingStorage.ActualLocation;
                    return false;
                }

                decimal? putawayQTY = Context.TPutawayOrders.AsNoTracking().Where(p => p.SourceType == 1 && p.RelatedOrderDetailId == orderDetail.Id).Sum(t => t.Qty).GetValueOrDefault();
                //最小库存单位
                materialNum = palletBind.MaterialPackageBindModel.Qty;
                
                bool hasSkuDetail = true;
                int stackingStorageId = Context.TStackingStorages.FirstOrDefault(s => s.PalletBarcode == palletBarcode && s.BatchNo == orderDetail.BatchNo && s.MaterialId == orderDetail.MaterialId && s.WarehouseCode == orderDetail.WarehouseCode && s.RelatedOrderDetailId == orderDetail.Id).Id;

                var receivingOrderDetail = Context.TReceivingOrderDetails.FirstOrDefault(x => x.Id == orderDetail.Id);

                //生成wms指令
                instruct = new TInstruct
                {
                    WarehouseCode = srcStation.WhCode,
                    Status = 2,
                    FromLocation = srcStation.Code,
                    ToLocation = "",
                    StackingStorageId = stackingStorageId,
                    WorkDeviceType = 2,
                    InstructType = 0,
                    Action = 0,
                    RelatedOrderDetailId = orderDetail.Id,
                    DeviceCode = "",
                    ExpectedToLocation = allocateCell.Code,
                    InstructIndex = 1,
                    PalletBarcode = palletBarcode,
                    ScanedBarcode = palletBarcode,
                    Priority = 9999,
                    Qty = (decimal)materialNum,
                    FinishedQty = 0,
                    StartTime = DateTime.Now,
                    BusinessGroupId = Guid.NewGuid(),
                    BusinessType = (int)EmBusinessType.In,
                    BillType = (int)orderDetail.BillType.GetValueOrDefault(),
                    LogicalCellAddr = allocateCell.Erpcode
                };
                Context.TInstructs.Add(instruct);

                if (Context.SaveChanges() <= 0)
                {
                    errorMsg = "指令保存失败";
                    return false;
                }

                //保存库存
                TInventory inventory = new TInventory()
                {
                    WarehouseId = allocateCell.WhId,
                    WarehouseCode = allocateCell.WhCode,
                    WarehouseName = allocateCell.WhName,
                    AreaCode = allocateCell.AreaCode,
                    AreaName = allocateCell.AreaName,
                    AreaId = allocateCell.AreaId,
                    //CompanyId = order.CompanyId,
                    //CompanyName = order.CompanyName,
                    LocationId = allocateCell.Id,
                    LocationCode = allocateCell.Code,
                    LocationDepth = allocateCell.DepthIndex,
                    LocationName = allocateCell.Name,
                    DictReceivingId = orderDetail.DictReceivingId,
                    DictReceiving = orderDetail.DictReceiving,
                    Status = 3,
                    //TaskId = instructs[0].TaskId,
                    PalletBarcode = palletBarcode,
                    ParentPalletBarcode = stackingStorage.ParentPalletBarcode,
                    //RelatedOrderId = orderDetail.OrderId,
                    RelatedOrderDetailId = orderDetail.Id,
                    BillType = (int)orderDetail.BillType.GetValueOrDefault(),
                    IsLock = true,
                    CreateDate = DateTime.Now,
                    MaterialId = orderDetail.MaterialId,
                    MaterialCode = orderDetail.MaterialCode,
                    MaterialName = orderDetail.MaterialName,
                    Articlebarcode = orderDetail.Articlebarcode,
                    CustomerId = orderDetail.CustomerId,
                    CustomerName = orderDetail.CustomerName,
                    HasSkuDetail = hasSkuDetail,
                    PutawayQty = materialNum,
                    UnitId = orderDetail.UnitId,
                    UnitName = orderDetail.UnitName,
                    MaterialKeyId = orderDetail.MaterialKeyId,
                    BatchNo = orderDetail.BatchNo,
                    SmallBatchNo = orderDetail.SmallBatchNo,
                    OwnerId = orderDetail.OwnerId,
                    OwnerName = orderDetail.OwnerName,
                    ExpireDate = orderDetail.ExpireDate,
                    ProductDate = orderDetail.ProductDate,
                    MaterialTypeCode = orderDetail.MaterialTypeCode,
                    MaterialTypeName = orderDetail.MaterialTypeName,
                    PickedQty = 0,
                    PackQty = packageBarcodes.Count,
                    ErplocationCode = allocateCell.Erpcode,
                    RoutewayId = allocateCell.RoutewayId,
                    StackingStorageId = stackingStorageId,
                    LocationHeightType = allocateCell.HeightType,
                    RealHeightType = heightType,
                    LogicalPartCode = orderDetail.LogicalPartCode,//按单据来
                    LocationColumnNo = allocateCell.ColumnNo,
                    LocationLayerNo = allocateCell.LayerNo,
                    LocationDistanceValue = allocateCell.DistanceValue,
                    LocationLineNo = allocateCell.LineNo,
                    DeptCode = orderDetail.DeptCode,
                    DeptName = orderDetail.DeptName,
                    TotalPrice = price * materialNum,
                    Price = price,
                    AvailableQty = palletBind.MaterialPackageBindModel.Qty,
                    AllocateQty = 0,
                    WhetherQualified = "合格",
                    TotalWeight = palletBind.MaterialPackageBindModel.Qty * GetMaterialTonnagefactor(orderDetail.MaterialCode),//总重量等于入库数量 * 物料吨数系数
                };
                Context.TInventories.Add(inventory);
                if (Context.SaveChanges() <= 0)
                {
                    errorMsg = "库存主表保存失败";
                    return false;
                }
                
                //保存上架单主表
                Random random = new Random(Guid.NewGuid().GetHashCode());
                int randNum = random.Next(1, 10000);
                string str = DateTime.Now.ToString("yyyyMMddHHmmssfff") + randNum.ToString("0000");
                string putawayCode = "PUT" + str;
                TPutawayOrder putawayOrder = new TPutawayOrder()
                {
                    Code = putawayCode,
                    RelatedOrderDetailId = orderDetail.Id,
                    StackingStorageId = stackingStorageId,
                    PalletBarcode = palletBarcode,
                    ParentPalletBarcode = stackingStorage.ParentPalletBarcode,
                    LocationCode = allocateCell.Code,
                    LocationDepth = allocateCell.DepthIndex == 0 ? null : allocateCell.DepthIndex,
                    Status = 4,
                    Qty = materialNum,
                    CreateDate = DateTime.Now,
                    MaterialId = orderDetail.MaterialId,
                    MaterialCode = orderDetail.MaterialCode,
                    MaterialName = orderDetail.MaterialName,
                    MaterialKeyId = orderDetail.MaterialKeyId,
                    BatchNo = orderDetail.BatchNo,
                    SmallBatchNo = orderDetail.SmallBatchNo,
                    OwnerId = orderDetail.OwnerId,
                    OwnerName = orderDetail.OwnerName,
                    CreateUserId = 0,
                    CreateUserName = "系统",
                    SourceType = 1,
                };
                Context.TPutawayOrders.Add(putawayOrder);
               
                if (Context.SaveChanges() <= 0)
                {
                    errorMsg = "上架单主表保存失败";
                    return false;
                }
                if (palletBind.MaterialPackageBindModel.Barcodes != null && palletBind.MaterialPackageBindModel.Barcodes.Count > 0)
                {
                    List<TPackageDetail> packageDetailList = Context.TPackageDetails.AsNoTracking().Where(p => p.RelatedOrderDetailId == orderDetail.Id && p.StackingStorageId == stackingStorageId && p.PackageCode == palletBarcode).ToList();
                    var packageDetail = packageDetailList.FirstOrDefault(t => t.PackageClass == 1 && t.ParentId == 0);
                    foreach (var item in palletBind.MaterialPackageBindModel.Barcodes)
                    {
                        //库存明细保存
                        TInventoryDetail inventoryDetail = new TInventoryDetail()
                        {
                            InventoryId = (int)inventory.Id,
                            Barcode = item,
                            PackageBarcode = palletBarcode,
                            PalletBarcode = palletBarcode,
                            CreateDate = DateTime.Now,
                            SkuNum = 1,
                            Price = price,
                            TotalPrice = price * 1,
                            IsSku = true,
                        };

                        var inventoryDetailId = Context.TInventoryDetails.Add(inventoryDetail);
                        if (Context.SaveChanges() <= 0)
                        {
                            errorMsg = "库存明细表保存失败";
                            return false;
                        }
                        //上架单明细表保存
                        TPutawayOrderDetail putawaydetail = new TPutawayOrderDetail()
                        {
                            PutawayOrderId = (int)putawayOrder.Id,
                            PalletBarcode = palletBarcode,
                            PackageBarcode = palletBarcode,// package.PackageBarcode
                            MaterialBarcode = item,
                        };
                        var putDetailId = Context.TPutawayOrderDetails.Add(putawaydetail);
                        if (Context.SaveChanges() <= 0)
                        {
                            errorMsg = "上架单明细表保存失败";
                            return false;
                        }
                        if (packageDetail != null)
                        {
                            if (packageDetailList.Any(t => t.Barcode == item))
                            {
                                continue;
                            }
                            TPackageDetail package = new TPackageDetail()
                            {
                                Status = 1,
                                RelatedOrderDetailId = orderDetail.Id,
                                MaterialId = orderDetail.MaterialId,
                                MaterialKeyId = orderDetail.MaterialKeyId,
                                MaterialCode = orderDetail.MaterialCode,
                                MaterialName = orderDetail.MaterialName,
                                PackageClass = 2,
                                BatchNo = orderDetail.BatchNo,
                                SmallBatchNo = orderDetail.SmallBatchNo,
                                Qty = 1,
                                UnitId = orderDetail.UnitId,
                                UnitName = orderDetail.UnitName,
                                ConvertFigre = 0,
                                Barcode = item,
                                PackageCode = palletBarcode,
                                LayerIndex = 1,
                                CreateDate = DateTime.Now,
                                StackingStorageId = stackingStorageId,
                                ParentId = packageDetail.Id,
                                IsStocktake = false,
                                CreateUserId = packageDetail.CreateUserId,
                                CreateUserName = packageDetail.CreateUserName,
                            };
                            var skuPkgId = Context.TPackageDetails.Add(package);
                            if (Context.SaveChanges() <= 0)
                            {
                                errorMsg = "保存组箱数据失败";
                                return false;
                            }
                        }
                    }
                }
                else
                {
                    //库存明细保存
                    TInventoryDetail inventoryDetail = new TInventoryDetail()
                    {
                        InventoryId = (int)inventory.Id,
                        Barcode = "",
                        PackageBarcode = palletBarcode,// package.PackageBarcode
                        PalletBarcode = palletBarcode,
                        CreateDate = DateTime.Now,
                        SkuNum = materialNum,
                        IsSku = false,
                        Price = price,
                        TotalPrice = price * materialNum
                    };
                    Context.TInventoryDetails.Add(inventoryDetail);
                    if (Context.SaveChanges() <= 0)
                    {
                        errorMsg = "库存明细表保存失败";
                        return false;
                    }
                    //上架单明细表保存
                    TPutawayOrderDetail putawayOrderDetail = new TPutawayOrderDetail()
                    {
                        PutawayOrderId = (int)putawayOrder.Id,
                        PalletBarcode = palletBarcode,
                        PackageBarcode = palletBarcode,//package.PackageBarcode
                        MaterialBarcode = "",
                    };
                    Context.TPutawayOrderDetails.Add(putawayOrderDetail);

                    if (Context.SaveChanges() <= 0)
                    {
                        errorMsg = "上架单明细表保存失败";
                        return false;
                    }

                }
                if (receivingOrderDetail.Qty == receivingOrderDetail.StackedQty)
                {
                    var isok = ExecInstructFinished(instruct, out errorMsg);
                    if (!isok)
                    {
                        errorMsg = "入库失败" + errorMsg;
                        return false;
                    }
                }
                return true;
            }
        }

        /// <summary>
        /// 完成入库
        /// </summary>
        /// <param name="instruct"></param>
        /// <param name="errorMsg"></param>
        /// <returns></returns>
        private bool ExecInstructFinished(TInstruct instruct, out string errorMsg)
        {
            errorMsg = "";
            if (string.IsNullOrEmpty(instruct.PalletBarcode))
            {
                errorMsg = "参数错误";
                return false;
            }
            lock (_lockObj)
            {
                try
                {
                    var orderDetail = Context.TReceivingOrderDetails.FirstOrDefault(r => r.Id == instruct.RelatedOrderDetailId);
                    if (orderDetail == null)
                    {
                        errorMsg = "入库单明细不存在";
                        return false;
                    }
                    var inventory = Context.TInventory.FirstOrDefault(i => i.PalletBarcode == instruct.PalletBarcode);
                    if (inventory == null)
                    {
                        errorMsg = "库存数据不存在";
                        return false;
                    }
                    List<TInventoryDetail> inventoryDetailList = Context.TInventoryDetails.AsNoTracking().Where(i => i.InventoryId == inventory.Id).ToList();
                    if (inventoryDetailList == null || inventoryDetailList.Count == 0)
                    {
                        errorMsg = "库存明细数据不存在";
                        return false;
                    }
                    List<string> packageBarcodes = inventoryDetailList.Select(t => t.PackageBarcode).Distinct().ToList();
                    TCell cell = Context.TCells.FirstOrDefault(c => c.Code == instruct.ExpectedToLocation);
                    if (cell == null)
                    {
                        errorMsg = "仓位数据不存在";
                        return false;
                    }
                    DateTime? now = DateTime.Now;
                    bool result = false;
                    #region 事务处理
                    
                    var putawayOrder = Context.TPutawayOrders.FirstOrDefault(p => p.Status == 4 && p.RelatedOrderDetailId == orderDetail.Id && p.StackingStorageId == instruct.StackingStorageId);
                    putawayOrder.Status = 5;
                    putawayOrder.Fifodate = now;
                    Context.TPutawayOrders.Update(putawayOrder);
                    if (Context.SaveChanges() <= 0)
                    {
                        errorMsg = "上架单状态修改失败";
                        return false;
                    }

                    var inventory1 = Context.TInventory.FirstOrDefault(i => i.Id == inventory.Id);
                    inventory1.Status = 1;
                    inventory1.AllocateQty = instruct.Qty;
                    inventory1.InStockDate = now;
                    inventory1.InStockShortDate = Convert.ToInt32(now.Value.ToString("yyyyMMdd"));
                    inventory1.PutawayQty = instruct.Qty;
                    inventory1.IsLock = false;
                    Context.TInventory.Update(inventory1);
                    if (Context.SaveChanges() <= 0)
                    {
                        errorMsg = "库存状态修改失败";
                        return false;
                    }
                    var cell1 = Context.TCells.FirstOrDefault(c => c.Id == inventory.LocationId);
                    cell1.IsLock = false;
                    cell1.BusinessType = 0;
                    cell1.Status = 1;
                    cell1.FullStatus = 1;
                    cell1.ModifyDate = now;
                    Context.TCells.Update(cell1);
                    if (Context.SaveChanges() <= 0)
                    {
                        errorMsg = "仓位状态修改失败";
                        return false;
                    }
                    //查询组垛
                    bool isUpdateOrderDetail = true;
                    List<string> palletBarcodes = new List<string>();
                    var stackingStorage = Context.TStackingStorages.FirstOrDefault(s => s.Status == 1 && s.PalletBarcode == inventory.PalletBarcode);
                    List<TStackingStorage> stackingStorageModels = Context.TStackingStorages.AsNoTracking().Where(s => s.Status == 1 && (s.PalletBarcode == stackingStorage.PalletBarcode || s.ParentPalletBarcode == stackingStorage.PalletBarcode)).ToList();
                    if (stackingStorageModels.Count > 1)
                    {
                        //拆卸
                        palletBarcodes = stackingStorageModels.Select(t => t.PalletBarcode).Distinct().ToList();
                        int count = Context.TInventory.AsNoTracking().Where(i => i.Status == 1 && i.IsLock == false && palletBarcodes.Contains(i.PalletBarcode)).Count();
                        if (palletBarcodes.Count == count)
                        {
                            isUpdateOrderDetail = true;
                        }
                        else
                        {
                            isUpdateOrderDetail = false;
                        }
                    }
                    if (isUpdateOrderDetail)
                    {
                        decimal? totalPutawayQTY = Context.TPutawayOrders.AsNoTracking().Where(t => t.SourceType == 1 && t.RelatedOrderDetailId == orderDetail.Id && t.Status == 5).Sum(t => t.Qty);
                        TReceivingOrderDetail modifyOrderDetail = new TReceivingOrderDetail
                        {
                            ReceivedQty = totalPutawayQTY,
                            InStarDate = orderDetail.InStarDate == null ? now : orderDetail.InStarDate,
                        };
                        if (totalPutawayQTY.GetValueOrDefault() >= orderDetail.Qty.GetValueOrDefault())
                        {
                            modifyOrderDetail.Status = (int)EmBillStatus.Finished;
                        }

                        var receivingOrderDetail = Context.TReceivingOrderDetails.FirstOrDefault(r => r.Id == orderDetail.Id);
                        receivingOrderDetail.ReceivedQty = modifyOrderDetail.ReceivedQty;
                        receivingOrderDetail.InStarDate = modifyOrderDetail.InStarDate;
                        receivingOrderDetail.Status = modifyOrderDetail.Status;
                        Context.TReceivingOrderDetails.Update(receivingOrderDetail);
                        if (Context.SaveChanges() <= 0)
                        {
                            errorMsg = "订单明细修改失败";
                            return false;
                        }
                    }
                    //保存库存日志表
                    //int logId = inventoryLogService.InsertInventoryLog(context, 
                    //如果是回流入库就不填库存流水
                    if (orderDetail.SourceType == 4)
                    {
                        //数量的修改可以先把库存数量修改为0 然后把需要修改的数据赋到入库单上
                        return true;
                    }
                    TInventoryLog inventoryLog = new TInventoryLog()
                    {
                        SourceType = 0,
                        SourceSn = orderDetail.OrderSn,
                        WarehouseId = orderDetail.WarehouseId,
                        WarehouseName = orderDetail.WarehouseName,
                        AreaName = inventory.AreaName,
                        AreaId = inventory.AreaId,
                        LocationCode = inventory.LocationCode,
                        PalletBarcode = instruct.PalletBarcode,
                        OwnerId = orderDetail.OwnerId,
                        OwnerName = orderDetail.OwnerName,
                        MaterialId = orderDetail.MaterialId,
                        MaterialCode = orderDetail.MaterialCode,
                        MaterialName = orderDetail.MaterialName,
                        BatchNo = orderDetail.BatchNo,
                        SmallBatchNo = orderDetail.SmallBatchNo,
                        StartQty = 0,
                        ChangeQty = instruct.Qty,
                        EndQty = instruct.Qty,
                        BaseUnitId = orderDetail.UnitId,
                        BaseUnitName = orderDetail.UnitName,
                        CreateDate = DateTime.Now,
                    };
                    Context.TInventoryLogs.Add(inventoryLog);
                    if (Context.SaveChanges() <= 0)
                    {
                        errorMsg = "库存日志表保存失败";
                        return false;
                    }
                    return true;
                    #endregion
                }
                catch (Exception ex)
                {
                    errorMsg = ex.Message;
                    return false;
                    throw;
                }
            }
        }

        /// <summary>
        /// 查询总重量
        /// </summary>
        /// <param name="materCode"></param>
        /// <returns></returns>
        private decimal GetMaterialTonnagefactor(string materCode)
        {
            var res = Context.TMaterial.FirstOrDefault(s => s.Code == materCode);
            if (res == null)
            {
                return 0;
            }
            return res.Tonnagefactor;
        }


        /// <summary>
        /// 判断数据
        /// </summary>
        /// <param name="orderDetailId"></param>
        /// <returns></returns>
        private (bool, string, TReceivingOrderDetail) ValidateStatusEF(int? orderDetailId)
        {
            var orderObj = Context.TReceivingOrderDetails.Find(orderDetailId);
            if (orderObj == null)
            {
                return (false, "未找到入库单", null);
            }
            TReceivingOrderDetail orderDetail = orderObj;

            if (orderDetail.Status == 0 || orderDetail.Status == 1)
            {
                return (false, "入库单未审核", null);
            }
            if (orderDetail.Status == 4 || orderDetail.Status == 5)
            {
                return (false, "入库单已完成", null);
            }

            if (orderDetail.Status != 2 && orderDetail.Status != 3)
            {
                return (false, "入库单状态有误", null);
            }
            return (true, string.Empty, orderDetail);
        }

        /// <summary>
        /// 获取一个仓位
        /// </summary>
        /// <returns></returns>
        private TCell GetOneCell(TStation srcStation, TReceivingOrderDetail orderDetail, int heightType, out string errorMsg, Model.Models.PalletBindMaterialModel palletBindMaterialModel)
        {
            var stackingStorage = Context.TStackingStorages.FirstOrDefault(s => s.BatchNo == orderDetail.BatchNo && s.MaterialId == orderDetail.MaterialId && s.WarehouseCode == orderDetail.WarehouseCode && s.RelatedOrderDetailId == orderDetail.Id && s.PalletBarcode == palletBindMaterialModel.PalletBarcode);
            var pallet = Context.TPallets.FirstOrDefault(x => x.PalletBarcode == palletBindMaterialModel.PalletBarcode);

            if (stackingStorage == null || string.IsNullOrEmpty(stackingStorage.LogicalPartCode))
            {
                errorMsg = "未选择逻辑分区";
                return null;
            }
            if (stackingStorage.LogicalPartCode == "Box8060" && pallet.Type != 1)
            {
                errorMsg = "逻辑分区与料箱不匹配";
                return null;
            }
            else if (stackingStorage.LogicalPartCode == "Box6040" && pallet.Type != 2)
            {
                errorMsg = "逻辑分区与料箱不匹配";
                return null;
            }

            var allocateCell = TCellRepository.AllocateCell(srcStation, (int)orderDetail.MaterialId.GetValueOrDefault(), (int)orderDetail.MaterialKeyId.GetValueOrDefault(), orderDetail.QualityState, heightType, out errorMsg, stackingStorage.LogicalPartCode);

            return allocateCell;
        }
    }
}
